package com.mia.props;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mia.craftstudio.CSModel;
import com.mia.craftstudio.IPackReaderCallback;
import com.mia.craftstudio.api.ICSProject;
import com.mia.craftstudio.minecraft.ModelMetadata;
import com.mia.craftstudio.minecraft.forge.CSLibMod;
import com.mia.props.client.container.GuiHandler;
import com.mia.props.common.BlockFake;
import com.mia.props.common.BlockProps;
import com.mia.props.common.ItemCratingClay;
import com.mia.props.common.ItemDecowand;
import com.mia.props.common.ItemProps;
import com.mia.props.common.TileFake;
import com.mia.props.common.TileTypeMap;
import com.mia.props.common.entities.EntityChairMount;
import com.mia.props.common.entities.TileDecobench;
import com.mia.props.events.CommonProxy;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.ProgressManager;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import cpw.mods.fml.relauncher.ReflectionHelper;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.ChunkCache;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapedOreRecipe;
import net.minecraftforge.oredict.ShapelessOreRecipe;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

@Mod(
   modid = "props",
   name = "DecoCraft",
   version = "2.4.2",
   dependencies = "after:PTRModelLib@[1.0.0,)"
)
public class Props {
   @Instance("props")
   public static Props instance;
   @SidedProxy(
      clientSide = "com.mia.props.events.ClientProxy",
      serverSide = "com.mia.props.events.CommonProxy"
   )
   public static CommonProxy proxy;
   public static final String modid = "props";
   public static Logger log = LogManager.getLogger("props");
   public static Block blockProps;
   public static Block blockFake;
   public static Item itemProps;
   public static Item itemClay;
   public static ItemDecowand itemTool;
   public static HashSet recipes = new HashSet();
   public static Map modelData = new HashMap() {
      public DecoModelMetadata get(Object key) {
         return super.containsKey(key) ? (DecoModelMetadata)super.get(key) : (DecoModelMetadata)super.get(0);
      }
   };
   public static ICSProject csproject;
   public HashMap modelDataVariantsList = new HashMap();
   private static Configuration config = null;
   public static boolean clayRecipe = true;
   public static boolean clayDrops = false;
   public static boolean allowPropRecycling = true;
   public static boolean enabledOldStyleRecipes = false;
   public static final HashSet allowableResourceItems = new HashSet();

   @EventHandler
   public void loadComplete(FMLLoadCompleteEvent event) {
      allowableResourceItems.add(new ItemStack(itemClay, 1, 32767));
      if (allowPropRecycling) {
         allowableResourceItems.add(new ItemStack(itemProps, 1, 32767));
      }

      allowableResourceItems.add(new ItemStack(Items.clay_ball));
      allowableResourceItems.add(new ItemStack(Blocks.clay));
      TileDecobench.DyeResourceMap[] var2 = TileDecobench.DyeResourceMap.values();
      int var3 = var2.length;

      for(int var4 = 0; var4 < var3; ++var4) {
         TileDecobench.DyeResourceMap dyeMap = var2[var4];
         ArrayList dyesFound = OreDictionary.getOres(dyeMap.name());
         Iterator var7 = dyesFound.iterator();

         while(var7.hasNext()) {
            ItemStack dye = (ItemStack)var7.next();
            allowableResourceItems.add(dye);
         }
      }

   }

   @EventHandler
   public void init(FMLInitializationEvent event) {
      proxy.init();
   }

   @EventHandler
   public void preInit(FMLPreInitializationEvent ev) {
      config = new Configuration(ev.getSuggestedConfigurationFile());

      try {
         config.load();
         clayRecipe = config.getBoolean("clayRecipe", "general", true, "");
         clayDrops = config.getBoolean("clayDrops", "general", false, "");
         allowPropRecycling = config.getBoolean("allowPropRecycling", "general", true, "Allow old props to be turned back in to resources at the decobench?");
         enabledOldStyleRecipes = config.getBoolean("enabledOldStyleRecipes", "general", false, "Enable old style crafting recipes using crafting clay.");
      } catch (Exception var6) {
         FMLLog.severe("Decocraft has a problem loading it's configuration", new Object[0]);
         FMLLog.severe(var6.getMessage(), new Object[0]);
         throw new RuntimeException(var6);
      } finally {
         if (config.hasChanged()) {
            config.save();
         }

      }

      NetworkRegistry.INSTANCE.registerGuiHandler(this, new GuiHandler());
      blockProps = new BlockProps();
      blockFake = new BlockFake();
      itemProps = new ItemProps();
      itemClay = new ItemCratingClay();
      itemTool = new ItemDecowand();
      GameRegistry.registerBlock(blockProps, "blockProps");
      GameRegistry.registerBlock(blockFake, "blockFake");
      GameRegistry.registerItem(itemProps, "props");
      GameRegistry.registerItem(itemClay, "clay");
      GameRegistry.registerItem(itemTool, "tool");
      int id = EntityRegistry.findGlobalUniqueEntityId();
      EntityRegistry.registerGlobalEntityID(EntityChairMount.class, "FakeChairEntity", id);
      EntityRegistry.registerModEntity(EntityChairMount.class, "FakeChairEntity", id, "props", 80, 3, true);
      GameRegistry.registerTileEntity(TileFake.class, "TileFake");
      TileTypeMap.register();
      if (clayRecipe) {
         GameRegistry.addRecipe(new ShapelessOreRecipe(new ItemStack(itemClay, 4, 0), new Object[]{Blocks.sand, Blocks.dirt, "dyeRed"}));
         GameRegistry.addRecipe(new ShapelessOreRecipe(new ItemStack(itemClay, 4, 1), new Object[]{Blocks.sand, Blocks.dirt, "dyeBlue"}));
         GameRegistry.addRecipe(new ShapelessOreRecipe(new ItemStack(itemClay, 4, 2), new Object[]{Blocks.sand, Blocks.dirt, "dyeGreen"}));
      }

      File modelListOverride = new File(ev.getModConfigurationDirectory(), "decocraftModelList.json");

      try {
         InputStream overrideStream = modelListOverride.exists() ? new FileInputStream(modelListOverride) : null;
         this.loadModels(overrideStream);
      } catch (FileNotFoundException var10) {
         var10.printStackTrace();
      }
      GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(itemProps, 1, 508), new Object[]{" R ", "GTB", 'R', new ItemStack(itemClay, 1, 0), 'G', new ItemStack(itemClay, 1, 1), 'B', new ItemStack(itemClay, 1, 2), 'T', Blocks.crafting_table}));
      GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(itemProps, 1, 508), new Object[]{" R ", "GTB", " C ", 'R', "dyeRed", 'G', "dyeGreen", 'B', "dyeBlue", 'T', Blocks.crafting_table, 'C', Blocks.clay}));
      GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(itemTool), new Object[]{"W", "C", "S", 'W', Blocks.wool, 'C', new ItemStack(itemProps, 1, 508), 'S', "stickWood"}));
      proxy.preInit();
   }

   private void validateModelMetadata(DecoModelMetadata metaData, CSModel model, ArrayList variantsList) {
      if (modelData.containsKey(metaData.decocraftModelID)) {
         DecoModelMetadata existingMeta = (DecoModelMetadata)modelData.get(metaData.decocraftModelID);
         if (!existingMeta.craftstudioAssetName.equals(metaData.craftstudioAssetName)) {
            throw new RuntimeException("You gave a new model the same DecoID as an existing model! Existing:[" + existingMeta.craftstudioAssetName + "], New:[" + metaData.craftstudioAssetName + "]");
         }

         recipes.remove(existingMeta.recipe);
      }

      variantsList.add(metaData.decocraftModelID);
      metaData.csmodel = model;
      metaData.validate();
      modelData.put(metaData.decocraftModelID, metaData);
      if (metaData.variants != null) {
         Iterator var6 = metaData.variants.entrySet().iterator();

         while(var6.hasNext()) {
            Entry entry = (Entry)var6.next();
//            this.validateModelMetadata(new DecoModelMetadata(metaData, (Integer)entry.getKey(), (JsonObject)entry.getValue()), model, variantsList);
         }
      }

   }

   public void loadModels(InputStream modelListOverride) {
      csproject = CSLibMod.getCSProjectAndLoad("Decopack", modelListOverride, new IPackReaderCallback() {
         private ProgressManager.ProgressBar progressBar = null;

         public void modelLoaded(CSModel model, JsonElement json) {
            if (json != null) {
               try {
                  this.progressBar.step(json.getAsJsonObject().get("name").getAsString());
               } catch (NullPointerException var4) {
                  Props.log.error("Critical error while parsing: " + json);
                  throw var4;
               }
            }

            if (this.progressBar.getStep() == this.progressBar.getSteps()) {
               ProgressManager.pop(this.progressBar);
            }

         }

         public void setCount(int count) {
            this.progressBar = ProgressManager.push("Loading models", count);
         }
      });
      Gson gson = (new GsonBuilder()).create();
      Iterator var2 = csproject.getModels().entrySet().iterator();

      while(true) {
         while(true) {
            Entry entry;
            JsonElement modelDescriptor;
            do {
               if (!var2.hasNext()) {
                  if (itemTool.modelMeta == null) {
                     Integer toolID = csproject.findFirstIDfromName("Item_DecoWand");
                     if (toolID >= 0) {
                        itemTool.modelMeta = new ModelMetadata();
                        itemTool.modelMeta.craftstudioAssetID = toolID;
                        itemTool.modelMeta.craftstudioAssetName = "Item_DecoWand";
                        itemTool.modelMeta.csmodel = csproject.getModel(toolID);
                        itemTool.modelMeta.scale = 2.5F;
                     }
                  }

                  proxy.setupModelWrappers();
                  return;
               }

               entry = (Entry)var2.next();
               modelDescriptor = csproject.getDescriptor((Integer)entry.getKey());
            } while(modelDescriptor == null);

            if ("item_decowand".equals(modelDescriptor.getAsJsonObject().get("craftstudioAssetName").getAsString().toLowerCase())) {
               itemTool.modelMeta = (ModelMetadata)gson.fromJson(modelDescriptor, ModelMetadata.class);
               itemTool.modelMeta.csmodel = (CSModel)entry.getValue();
            } else {
               ArrayList variantsList = new ArrayList();
               this.validateModelMetadata((DecoModelMetadata)gson.fromJson(modelDescriptor, DecoModelMetadata.class), (CSModel)entry.getValue(), variantsList);
               if (variantsList.size() > 1) {
                  this.modelDataVariantsList.put(variantsList.get(0), new Props.MetaVariantListNode((Integer)variantsList.get(variantsList.size() - 1), (Integer)variantsList.get(1), (Integer)variantsList.get(0)));
                  this.modelDataVariantsList.put(variantsList.get(variantsList.size() - 1), new Props.MetaVariantListNode((Integer)variantsList.get(variantsList.size() - 2), (Integer)variantsList.get(0), (Integer)variantsList.get(0)));
                  int i = 1;

                  for(int end = variantsList.size() - 1; i < end; ++i) {
                     this.modelDataVariantsList.put(variantsList.get(i), new Props.MetaVariantListNode((Integer)variantsList.get(i - 1), (Integer)variantsList.get(i + 1), (Integer)variantsList.get(0)));
                  }
               }
            }
         }
      }
   }

   public static TileEntity getTileEntityPreferNotCreating(IBlockAccess blockAccess, int x, int y, int z) {
      if (blockAccess instanceof World) {
         return getTileEntityWithoutCreating((World)blockAccess, x, y, z);
      } else {
         return blockAccess instanceof ChunkCache ? getTileEntityWithoutCreating((World) ReflectionHelper.getPrivateValue(ChunkCache.class, (ChunkCache)blockAccess, "worldObj", "field_72815_e", "e"), x, y, z) : blockAccess.getTileEntity(x, y, z);
      }
   }

   public static TileEntity getTileEntityWithoutCreating(World world, int x, int y, int z) {
      return world.blockExists(x, y, z) ? world.getChunkFromBlockCoords(x, z).getTileEntityUnsafe(x & 15, y, z & 15) : null;
   }

   public static class MetaVariantListNode {
      public Integer prevID;
      public Integer nextID;
      public Integer headID;

      public MetaVariantListNode(Integer p, Integer n, Integer h) {
         this.prevID = p;
         this.nextID = n;
         this.headID = h;
      }

      public String toString() {
         return "prevID: [" + this.prevID + "], nextID: [" + this.nextID + "], headID: [" + this.headID + "]";
      }
   }
}
